﻿
Public Module _deserializer
    'convert bytes into a structure
    Public Function deserialize(ByVal buff() As Byte,
                                ByVal start As Int64,
                                ByVal size As Int64,
                                ByVal insert As void(Of Byte())) As Boolean
        Dim [end] As Int64 = 0
        [end] = start
        If Not safe_increase([end], size) OrElse start < 0 OrElse size < 0 Then
            raiseError(errorHandle.errorType.exclamation,
                       "invalid start & size got, start = ", start, ", size = ", size,
                       ", ignore, callstack @ ", callstack())
            Return False
        End If
        If buff Is Nothing OrElse [end] > buff.Length() OrElse insert Is Nothing Then
            raiseError(errorHandle.errorType.warning, "the input buff is not enough for deserialize")
            Return False
        Else

            Dim p As Int64 = 0
            p = start
            While p < [end]
                Dim sz As Int64 = 0
                If convertor.toint64(buff, sz, p) AndAlso p <= [end] Then
                    If sz > maxInt32 OrElse sz < 0 Then
                        raiseError(errorHandle.errorType.exclamation, "invalid size ", size, " read, ignore following")
                        Exit While
                    End If
                    Dim b() As Byte = Nothing
                    ReDim b(sz - 1)
                    memcpy(b, 0, buff, p, sz)
                    p += sz
                    insert(b)
                Else
                    Exit While
                End If
            End While

            Return True
        End If
    End Function

    Public Function deserialize(ByVal buff() As Byte,
                                ByVal start As Int64,
                                ByVal size As Int64,
                                ByRef paras() As bytes) As Boolean
        Dim count As Int64 = 0
        Dim p() As bytes = Nothing
        ReDim p(3)
        If deserialize(buff, start, size,
                       Sub(ByRef b As Byte())
                           If count > 0 Then
                               assert(object_compare(b, +p(count - 1)) <> 0)
                           End If
                           count += 1
                           If p.Length() = count Then
                               ReDim Preserve p((p.Length() << 1) - 1)
                           End If
                           Dim bts As bytes = Nothing
                           bts = New bytes()
                           bts.attach(b)
                           p(count - 1) = bts
                       End Sub) Then
            ReDim Preserve p(count - 1)
            paras = p
            Return True
        Else
            Return False
        End If
    End Function

    Public Function deserialize(ByVal buff() As Byte,
                                ByVal start As Int64,
                                ByVal size As Int64,
                                ByRef paras() As fromBytes) As Boolean
        Dim p() As bytes = Nothing
        If deserialize(buff, start, size, p) AndAlso
           Not p Is Nothing AndAlso p.Length() > 0 AndAlso (p.Length() And 1) = 0 Then
            ReDim paras((p.Length() >> 1) - 1)
            For i As Int64 = 0 To p.Length() - 1 Step 2
                Dim bs As bytesString = Nothing
                bs = New bytesString()
                bs.frombytes(p(i))
                If types_cache.get(Convert.ToString(bs), paras(i >> 1)) Then
                    paras(i >> 1).frombytes(p(i + 1))
                Else
                    paras(i >> 1) = types_cache.defaultTypeInstance
                End If
            Next

            Return True
        Else
            Return False
        End If
    End Function

    Private Function deserialize(ByVal buff() As Byte,
                                 ByVal start As Int64,
                                 ByVal size As Int64,
                                 ByVal t As _do(Of Int64, Type),
                                 ByRef paras() As fromBytes,
                                 Optional ByVal check_p_length As _do(Of Int64, Boolean) = Nothing) As Boolean
        Dim p() As bytes = Nothing
        If deserialize(buff, start, size, p) AndAlso
           Not p Is Nothing AndAlso p.Length() > 0 AndAlso
           do_(check_p_length, p.Length(), True) Then
            ReDim paras(p.Length() - 1)
            For i As Int64 = 0 To p.Length() - 1
                paras(i) = alloc(t(i))
                If paras(i) Is Nothing Then
                    raiseError(errorHandle.errorType.warning, "cannot alloc type ", t(i))
                    Return False
                End If
                paras(i).frombytes(p(i))
            Next

            Return True
        Else
            Return False
        End If
    End Function

    Public Function deserialize(ByVal buff() As Byte,
                                ByVal start As Int64,
                                ByVal size As Int64,
                                ByVal types() As Type,
                                ByRef paras() As fromBytes) As Boolean
        If isemptyarray(types) Then
            Return False
        Else
            Return deserialize(buff, start, size,
                               Function(ByRef i As Int64) As Type
                                   Return types(i)
                               End Function,
                               paras,
                               Function(ByRef i As Int64) As Boolean
                                   Return i = types.Length()
                               End Function)
        End If
    End Function

    Public Function deserialize(ByVal buff() As Byte,
                                ByVal start As Int64,
                                ByVal size As Int64,
                                ByVal t As Type,
                                ByRef paras() As fromBytes) As Boolean
        If t Is Nothing Then
            Return False
        Else
            Return deserialize(buff, start, size,
                               Function(ByRef i As Int64) As Type
                                   Return t
                               End Function,
                               paras)
        End If
    End Function

    Public Function deserialize(ByVal buff As bytes, ByRef paras() As fromBytes) As Boolean
        If buff Is Nothing Then
            Return False
        Else
            Return deserialize(+buff, 0, buff.size(), paras)
        End If
    End Function

    Public Function deserialize(ByVal buff As bytes, ByVal types() As Type, ByRef paras() As fromBytes) As Boolean
        If buff Is Nothing Then
            Return False
        Else
            Return deserialize(+buff, 0, buff.size(), types, paras)
        End If
    End Function

    Public Function deserialize(ByVal buff As bytes, ByVal t As Type, ByRef paras() As fromBytes) As Boolean
        If buff Is Nothing Then
            Return False
        Else
            Return deserialize(+buff, 0, buff.size(), t, paras)
        End If
    End Function
End Module
